package demo.utils;

import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.lang.Script;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 规则执行
 */
public class RuleExecutorUtil {

    private static Logger logger = LoggerFactory.getLogger(RuleExecutorUtil.class);


    private static final ConcurrentHashMap<String, Script> cache = new ConcurrentHashMap<>();

    /**
     * @param scriptText
     * @return
     */
    private static Script parseScript(String scriptText) {
        if (scriptText == null || scriptText.isEmpty()) {
            return null;
        }
        return cache.computeIfAbsent(scriptText, text -> {
            GroovyShell shell = new GroovyShell();
            Script script = shell.parse(text);
            logger.info("parse GroovyShell :{} ,cache.size = {}", scriptText, cache.size());
            System.out.printf("parse GroovyShell：%s, ,cache.size = %s\n", scriptText, cache.size());
            return script;
        });
    }

    /**
     * 执行脚本
     *
     * @param scriptText 脚本
     * @param variable   变量
     * @return
     */
    public static Object evaluate(String scriptText, Map variable) {
        if (scriptText == null || scriptText.isEmpty()) {
            return null;
        }
        Script script = parseScript(scriptText);
        if (script == null) {
            return null;
        }
        synchronized (script) {
            Binding binding = new Binding(variable);
            script.setBinding(binding);

            // 执行脚本
            Object value = script.run();

            // 执行结果
            String type = value.getClass().getCanonicalName();
            logger.debug("execute {} by {} return {} : {}", scriptText, variable, type, value);
            System.out.printf("执行结果：%s, 类型: %s\n", value, type);
            return value;
        }
    }

    static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(16);
        int i = 100_0000;
        while (i > 0) {
            executor.submit(() -> {
                String scriptText = "x > 30";
                Map variable = new HashMap();
                variable.put("x", random.nextInt(100));
                try {
                    Object result = evaluate(scriptText, variable);
                    System.out.println(result);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            Thread.sleep(1);
            i--;
        }
        executor.shutdown();
    }

    @Test
    public void test1() {
        org.codehaus.groovy.runtime.memoize.EvictableCache a = null;
        String scriptText = "x > 30";
        Map variable = new HashMap();
        variable.put("x", 40);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    @Test
    public void test2() {
        String scriptText = "x + y > 30";
        Map variable = new HashMap();
        variable.put("x", 20);
        variable.put("y", 10);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    @Test
    public void test3() {
        String scriptText = "(x + y) * z ";
        Map variable = new HashMap();
        variable.put("x", 2);
        variable.put("y", 10);
        variable.put("z", 3);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    /**
     * 与(&&)：逻辑规则是两真才真。与and等同。
     */
    @Test
    public void testAnd() {
        String scriptText = "x && y";
        Map variable = new HashMap();
        variable.put("x", true);
        variable.put("y", false);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    /**
     * 或(||)：逻辑规则是只有一个为真就为真。与or等同。
     */
    @Test
    public void testOr() {
        String scriptText = "x || y";
        Map variable = new HashMap();
        variable.put("x", true);
        variable.put("y", false);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    /**
     * 非(！)：逻辑规则是反转操作数的含义。与not等同。
     */
    @Test
    public void testNot() {
        String scriptText = "!x";
        Map variable = new HashMap();
        variable.put("x", true);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }

    /**
     * 异或(^)：逻辑规则是两个不同就为真。
     */
    @Test
    public void testXor() {
        String scriptText = "x ^ y";
        Map variable = new HashMap();
        variable.put("x", true);
        variable.put("y", false);
        Object result = evaluate(scriptText, variable);
        System.out.println(result);
    }
}
